package com.heima.admin.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.admin.mapper.AdChannelMapper;
import com.heima.admin.mapper.AdSensitiveMapper;
import com.heima.admin.service.WemediaNewsAutoScanService;
import com.heima.aliyun.GreeTextScan;
import com.heima.aliyun.GreenImageScan;
import com.heima.common.exception.CustException;
import com.heima.feigns.article.ArticleFeign;
import com.heima.feigns.wemedia.WemediaFeign;
import com.heima.model.admin.pojos.AdChannel;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import springfox.documentation.spring.web.json.Json;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
@Slf4j
@Transactional
public class WemediaNewsAutoScanServiceImpl implements WemediaNewsAutoScanService {

    @Autowired
    WemediaFeign wemediaFeign;


    @Autowired
    AdSensitiveMapper adSensitiveMapper;

    @Autowired
    GreeTextScan greeTextScan;

    @Autowired
    GreenImageScan greenImageScan;

    @Autowired
    AdChannelMapper adChannelMapper;

    @Autowired
    ArticleFeign articleFeign;

    @Value("${file.oss.web-site}")
    private String webSite;


    /**
     * 自动审核文章状态，发布文章
     *
     * @param wmNewsId 自媒体文章的ID
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void autoScanByMediaNewsId(Integer wmNewsId) {
        //参数检查
        if (wmNewsId == null) {
            log.error("autoScanByMediaNewsId wmNewsId is null");
            return;
        }

        //根据文章ID查询文章的信息
        WmNews wmNews = wemediaFeign.findById(wmNewsId);
        if (wmNews == null) {
            log.error("autoScanByMediaNewsId wmNews is null,id:{}", wmNewsId);
            return;
        }
        //判断文章的状态（如果文章状态=4并且发布时间小于等于当前时间，保存到文章库

        Short status = wmNews.getStatus();
        if (status.equals(WmNews.Status.ADMIN_SUCCESS.getCode()) &&
                wmNews.getPublishTime().getTime() <= System.currentTimeMillis()) {
            saveAppArticle(wmNews);
            return;
        }

        //如果文章状态=8，发布时间小于等于当前时间，直接保存到文章库）
        if (status.equals(WmNews.Status.SUCCESS.getCode()) &&
                wmNews.getPublishTime().getTime() <= System.currentTimeMillis()) {
            saveAppArticle(wmNews);
            return;
        }

        //文章状态=1时未审核
        if (status.equals(WmNews.Status.SUBMIT.getCode())) {
            //解析文章内容，获取文章图片和文本
            Map<String, Object> contentAndImagesResult = handleTextAndImages(wmNews);

            //自管理的敏感词(审核成功返回true，失败返回false且求改文章状态)
            boolean isSensitiveScan = handleSensitive((String) contentAndImagesResult.get(
                    "content"),
                    wmNews);

            if (!isSensitiveScan) return;

            //阿里云文本内容审核
            boolean isTextScan = handleTextScan((String) contentAndImagesResult.get(
                    "content"),
                    wmNews);

            if (!isTextScan) return;
            //阿里云的图片的审核
            boolean isImageScan = handleImageScan((List) contentAndImagesResult.get(
                    "images"),
                    wmNews);

            if (!isImageScan) return;
            //判断当前的发布时间大于当前时间的话 修改wmNews文章状态为8
            if (wmNews.getPublishTime().getTime()>System.currentTimeMillis()){
                updateWmNews(wmNews,WmNews.Status.SUCCESS.getCode(),"文章审核通过");
            }
        }


        //审核通过，保存文章相关信息（三张表），修改文章状态为9(已发布)
        saveAppArticle(wmNews);

        //TODO ES同步索引库
    }


    /**
     * 阿里云图片审核
     * @param images
     * @param wmNews
     * @return
     */
    private boolean handleImageScan(List<String> images, WmNews wmNews) {
        boolean flag =true;
        //图片去重
        images = images.stream().distinct().collect(Collectors.toList());

        try {
            Map map = greenImageScan.imageUrlScan(images);

            if (map.get("suggestion").equals("block")){
                flag=false;
                updateWmNews(wmNews,WmNews.Status.FAIL.getCode(),"审核失败，文章图片违规");
            }

            if (map.get("suggestion").equals("review")){
                updateWmNews(wmNews,WmNews.Status.ADMIN_AUTH.getCode(),"文章需要人工审核");
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("aliyun handleTextScan is error,EX:{},wmNewsId:{}",e,wmNews.getId());
            updateWmNews(wmNews,WmNews.Status.ADMIN_AUTH.getCode(),"阿里云审核失败，转人工审核");
        }
        return flag;
    }


    /**
     * 阿里云文本审核
     * @param content
     * @param wmNews
     * @return
     */
    private boolean handleTextScan(String content, WmNews wmNews) {
        boolean flag = true;
        if (content.length()>10000){
            flag=false;
            log.error("文本长度过长");
            return flag;
        }
        try {
            Map<String,String> map = greeTextScan.greeTextScan(content);
            if (map.get("suggestion").equals("block")){
                flag=false;
                updateWmNews(wmNews,WmNews.Status.FAIL.getCode(),"审核失败，文章内容中包含敏感词");
            }

            if (map.get("suggestion").equals("review")){
                updateWmNews(wmNews,WmNews.Status.ADMIN_AUTH.getCode(),"文章需要人工审核");
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("aliyun handleTextScan is error,EX:{},wmNewsId:{}",e,wmNews.getId());
            updateWmNews(wmNews,WmNews.Status.ADMIN_AUTH.getCode(),"阿里云审核失败，转人工审核");
        }

        return flag;
    }


    /**
     * 自管理敏感词的审核
     *
     * @param content
     * @param wmNews
     * @return
     */
    private boolean handleSensitive(String content, WmNews wmNews) {
        boolean flag = true;

        //敏感词词库
        List<String> sensitive = adSensitiveMapper.findAllSensitive();
        SensitiveWordUtil.initMap(sensitive);
        //匹配
        Map<String, Integer> map = SensitiveWordUtil.matchWords(content);
        if (map.size() > 0) {
            //文章内容包含敏感词
            log.info("文章内容包含敏感词" + map);
            flag = false;
            //修改文章的状态

            updateWmNews(wmNews,WmNews.Status.FAIL.getCode(),"文章内容包含敏感词" + map);

        }

        return flag;
    }

    /**
     * 修改文章状态
     * @param wmNews
     * @param code
     * @param reason
     */
    private void updateWmNews(WmNews wmNews, short code, String reason) {
        wmNews.setStatus(code);
        wmNews.setReason(reason);
        ResponseResult result = wemediaFeign.updateWmNews(wmNews);
        if(!result.getCode().equals(0)){
            CustException.cust(AppHttpCodeEnum.WEMEDIA_UPDATE_ERROR);
        }
    }


    /**
     * 抽取文章的文本和图片(包含封面的图片[不带前缀])
     *
     * @param wmNews
     * @return 图片需要带前缀
     */
    private Map<String, Object> handleTextAndImages(WmNews wmNews) {
        //获取文章内容并转换成对象
        String content = wmNews.getContent();
        if (StringUtils.isBlank(content)) {
            return null;
        }
        //解析内容文本
        List<Map> contentList = JSON.parseArray(content, Map.class);
        String contents = contentList.stream().filter(x -> x.get("type").equals("text"))
                .map(y -> y.get("value").toString()).collect(Collectors.joining("/////"));
        //文章标题 参与审核
        contents=wmNews.getTitle()+"////"+contents;
        //解析内容的图片
        List<String> images = contentList.stream().filter(x -> x.get("type").equals("image"))
                .map(y -> y.get("value").toString()).collect(Collectors.toList());

        //处理封面的前缀
        String imageCover = wmNews.getImages();
        if (StringUtils.isNotBlank(imageCover)) {
            //处理图片的前缀并添加到内容图片列表
            images.addAll(
                    Stream.of(imageCover.split(","))
                            .map(x -> webSite + x).collect(Collectors.toList()));
        }
        //封装结果
        HashMap<String, Object> resultMap = new HashMap<>();
        resultMap.put("content", contents);
        resultMap.put("images", images);


        return resultMap;
    }


    /**
     * 保存文章数据
     *
     * @param wmNews
     */
    private void saveAppArticle(WmNews wmNews) {
        ResponseResult result=saveArticle(wmNews);

        if (result.getCode()!=0){
            throw new RuntimeException("文章审核保存app文章失败");
        }
        wmNews.setArticleId((Long) result.getData());

        //更新自媒体文章的状态为9
        updateWmNews(wmNews,WmNews.Status.PUBLISHED.getCode(),"已发布");
    }


    /**
     * 执行保存文章的方法
     * @param wmNews
     * @return
     */
    private ResponseResult saveArticle(WmNews wmNews) {
        //封装数据到Dto中
        ArticleDto articleDto = new ArticleDto();
        BeanUtils.copyProperties(wmNews,articleDto);
        articleDto.setId(null);
        if (wmNews.getArticleId()!=null){
            articleDto.setId(wmNews.getArticleId());
        }
        // 布局
        articleDto.setLayout(wmNews.getType());
        articleDto.setFlag((byte) 0);

        //2 设置频道
        if (wmNews.getChannelId() != null) {
            articleDto.setChannelId(wmNews.getChannelId());
            AdChannel channel = adChannelMapper.selectById(wmNews.getChannelId());
            if (channel != null) {
                articleDto.setChannelName(channel.getName());
            }
        }

        //3 设置作者信息
        // 查wm_user 状态
        WmUser wmUser = wemediaFeign.findWmUserById(wmNews.getUserId());
        if (wmUser == null || wmUser.getStatus().intValue() != 9) { // 非法用户
            CustException.cust(AppHttpCodeEnum.ADMIN_USER_ISNTOEXIT_ERROR);
        }
        if (StringUtils.isNotBlank(wmUser.getName())) {
            // 自媒体名称不能修改
            articleDto.setAuthorName(wmUser.getName());
            // 作者id 尽量减少远程调用
        }

        //4 文章内容
        articleDto.setContent(wmNews.getContent());




        return articleFeign.savaArticle(articleDto);
    }
}
